package org.jsola.hr.service.impl;

import com.alibaba.excel.EasyExcel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.lang3.StringUtils;
import org.jsola.common.BeanKit;
import org.jsola.core.Page;
import org.jsola.hr.common.ExampleKit;
import org.jsola.hr.common.ExcelKit;
import org.jsola.hr.constant.HrConstants;
import org.jsola.hr.dao.IEmpPositionDAO;
import org.jsola.hr.dto.*;
import org.jsola.hr.dto.excel.EmpInfoImportDTO;
import org.jsola.hr.entity.EmpInfoDO;
import org.jsola.hr.entity.EmpPositionDO;
import org.jsola.hr.provider.IFileProviderService;
import org.jsola.hr.query.EmpPositionQuery;
import org.jsola.hr.service.IEmpInfoService;
import org.jsola.hr.service.IEmpPositionService;
import org.jsola.hr.service.IPositionInfoService;
import org.jsola.hr.service.excel.EmpPaperContractListener;
import org.jsola.hr.vo.*;
import org.jsola.user.core.TokenUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import tk.mybatis.mapper.entity.Example;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author zhr
 */
@Service("hrEmpPositionServiceImpl")
@Slf4j
public class EmpPositionServiceImpl implements IEmpPositionService {

    @Autowired
    private IEmpPositionDAO empPositionDAO;

    @Autowired
    private IPositionInfoService positionInfoService;

    @Autowired
    @Lazy
    private IEmpInfoService empInfoService;

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public EmpPositionVO save(EmpPositionAddDTO empPositionAddDTO, TokenUser tokenUser) {

        EmpPositionVO empPositionVO = selectByEmpAndPosition(
                empPositionAddDTO.getCompanyId(),
                empPositionAddDTO.getEmpId(),
                empPositionAddDTO.getPositionId(),
                tokenUser.getSiteId());
        if (!Objects.isNull(empPositionVO)) {
            return empPositionVO;
        }

        // 转DO
        EmpPositionDO empPositionDO = empPositionAddDTO.to(EmpPositionDO.class);
        // 保存
        empPositionDO = save(empPositionDO, tokenUser.getSiteId(), tokenUser.getUserId());
        return empPositionDO.to(EmpPositionVO.class);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public List<EmpPositionVO> batchSave(List<EmpPositionAddDTO> empPositionAddDTOList, TokenUser tokenUser) {
        if (CollectionUtils.isEmpty(empPositionAddDTOList)) {
            return null;
        }
        List<EmpPositionDO> empPositionDOList = empPositionAddDTOList
                .parallelStream()
                .map(empPositionAddDTO -> {
                    EmpPositionDO empPositionDO = empPositionAddDTO.to(EmpPositionDO.class);
                    empPositionDO.preInsert(tokenUser.getUserId());
                    empPositionDO.setSiteId(tokenUser.getSiteId());
                    return empPositionDO;
                }).collect(Collectors.toList());
        empPositionDAO.insertListAndSetId(empPositionDOList);
        return empPositionDOList
                .parallelStream()
                .map(empPositionDO -> empPositionDO.to(EmpPositionVO.class))
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int update(EmpPositionUpdateDTO empPositionUpdateDTO, TokenUser tokenUser) {
        //转DO
        EmpPositionDO empPositionDO = empPositionUpdateDTO.to(EmpPositionDO.class);
        //根据主键更新，只更新非null值
        return updateByIdSelective(empPositionDO, tokenUser.getSiteId(), tokenUser.getUserId());
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int deleteByIds(TokenUser tokenUser, String... empPositionIds) {
        return deleteByIds(tokenUser.getSiteId(), tokenUser.getUserId(), (Object[]) empPositionIds);
    }


    @Override
    public EmpPositionVO selectById(String empPositionId, String siteId) {
        EmpPositionDO empPositionDO = selectDOById(empPositionId, siteId);
        if (empPositionDO == null) {
            return null;
        }
        return empPositionDO.to(EmpPositionVO.class);
    }

    @Override
    public List<EmpPositionListVO> select(EmpPositionQuery empPositionQuery, String siteId) {
        List<EmpPositionDO> empPositionDOList = selectDO(empPositionQuery, siteId);
        if (CollectionUtils.isEmpty(empPositionDOList)) {
            return empPositionDOList == null ? null : new ArrayList<>();
        }
        return empPositionDOList.stream()
                .map(empPositionDO -> empPositionDO.to(EmpPositionListVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public int selectCount(EmpPositionQuery empPositionQuery, String siteId) {
        Example example = buildExample(empPositionQuery, siteId);
        return empPositionDAO.selectCountByExample(example);
    }

    @Override
    public Page<EmpPositionListVO> selectPage(EmpPositionQuery empPositionQuery, String siteId) {
        Example example = buildExample(empPositionQuery, siteId);
        Page<EmpPositionDO> page = empPositionDAO.selectPageByExample(example,
                empPositionQuery.getPageNo(),
                empPositionQuery.getPageSize());

        return page.to(EmpPositionListVO.class);
    }

    @Override
    public EmpPositionDO selectDOById(String empPositionId, String siteId) {
        return listById(empPositionId, siteId);
    }

    @Override
    public List<EmpPositionDO> selectDO(EmpPositionQuery empPositionQuery, String siteId) {
        Example example = buildExample(empPositionQuery, siteId);
        return empPositionDAO.selectByExample(example);
    }

    @Override
    public List<EmpPositionDO> selectByExample(Example example) {
        return empPositionDAO.selectByExample(example);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void deleteByCompanyId(String companyId, TokenUser tokenUser) {
        Example example = new Example(EmpPositionDO.class);
        example.and()
                .andEqualTo("companyId", companyId)
                .andEqualTo("siteId", tokenUser.getSiteId());

        empPositionDAO.deleteByExample(example);
        ;
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void publishEmpPositionList(List<EmpPositionAddDTO> empPositionAddList, TokenUser tokenUser) {
        if (CollectionUtils.isEmpty(empPositionAddList)) {
            return;
        }
        // 删除某个员工所有的
        String empId = empPositionAddList.get(0).getEmpId();
        deleteByEmpId(empId, tokenUser);

        empPositionAddList.forEach(
                empPositionAddDTO -> {
                    EmpPositionVO empPositionVO = selectByEmpAndPosition(
                            empPositionAddDTO.getCompanyId(),
                            empPositionAddDTO.getEmpId(),
                            empPositionAddDTO.getPositionId(),
                            tokenUser.getSiteId());

                    // 没有就新增,有就这些参数,不用修改了
                    if (Objects.isNull(empPositionVO)) {
                        save(empPositionAddDTO, tokenUser);
                    }
                }
        );
        String positionIds = empPositionAddList.parallelStream().map(EmpPositionAddDTO::getPositionId)
                .distinct().collect(Collectors.joining(","));
        EmpInfoDO empInfoDO = new EmpInfoDO();
        empInfoDO.setId(empId);
        empInfoDO.setPreJoinPosition(positionIds);
        empInfoService.updateByIdSelective(empInfoDO, tokenUser.getSiteId(), tokenUser.getUserId());
    }

    /**
     * 删除某个用户所有的
     *
     * @param empId     用户 id
     * @param tokenUser 当前用户
     */
    private void deleteByEmpId(String empId, TokenUser tokenUser) {
        Example example = new Example(EmpPositionDO.class);
        example.and()
                .andEqualTo("empId", empId)
                .andEqualTo("siteId", tokenUser.getSiteId());

        empPositionDAO.deleteByExample(example);
    }

    @Override
    public EmpPositionVO selectByEmpAndPosition(String companyId, String empId, String positionId, String siteId) {
        Example example = new Example(EmpPositionDO.class);
        example.and()
                .andEqualTo("empId", empId)
                .andEqualTo("positionId", positionId)
                .andEqualTo("companyId", companyId)
                .andEqualTo("siteId", siteId);
        EmpPositionDO empPositionDO = empPositionDAO.selectOneByExample(example);
        if (Objects.isNull(empPositionDO)) {
            return null;
        }
        return empPositionDO.to(EmpPositionVO.class);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void deleteByEmpPosition(String companyId, String empId, String positionId, TokenUser tokenUser) {
        if (StringUtils.isEmpty(companyId) ||
                StringUtils.isEmpty(empId) ||
                StringUtils.isEmpty(positionId) ||
                StringUtils.isEmpty(tokenUser.getSiteId())) {
            return;
        }

        Example example = new Example(EmpPositionDO.class);
        example.and()
                .andEqualTo("empId", empId)
                .andEqualTo("positionId", positionId)
                .andEqualTo("companyId", companyId)
                .andEqualTo("siteId", tokenUser.getSiteId());

        empPositionDAO.deleteByExample(example);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void saveEmpPositions(String companyId, String empId, List<String> positionIdList, TokenUser tokenUser) {
        if (CollectionUtils.isEmpty(positionIdList)) {
            return;
        }
        // 删除某个员工原所有的
        deleteByEmpId(empId, tokenUser);

        positionIdList.forEach(
                positionId -> {
                    PositionInfoVO positionInfoVO = positionInfoService.selectById(positionId, tokenUser.getSiteId());
                    if (!Objects.isNull(positionInfoVO)) {
                        EmpPositionAddDTO empPositionAddDTO = new EmpPositionAddDTO();
                        empPositionAddDTO.setCompanyId(companyId);
                        empPositionAddDTO.setEmpId(empId);
                        empPositionAddDTO.setPositionId(positionId);

                        save(empPositionAddDTO, tokenUser);
                    }
                }
        );
    }

    /**
     * 根据查询参数，构建example
     *
     * @param empPositionQuery 查询参数
     * @param siteId           所属站点id
     * @return example
     */
    private Example buildExample(EmpPositionQuery empPositionQuery, String siteId) {
        Example example = new Example(EmpPositionDO.class);
        example.and()
                .andEqualTo("siteId", siteId);
        if (empPositionQuery.getEmpId() != null) {
            example.and().andLike("empId", "%" + empPositionQuery.getEmpId() + "%");
        }
        if (empPositionQuery.getPositionId() != null) {
            example.and().andLike("positionId", "%" + empPositionQuery.getPositionId() + "%");
        }
        if (empPositionQuery.getCompanyId() != null) {
            example.and().andEqualTo("companyId", empPositionQuery.getCompanyId());
        }
        if (empPositionQuery.getGmtCreateStart() != null &&
                empPositionQuery.getGmtCreateEnd() != null) {
            example.and().andBetween("gmtCreate", empPositionQuery.getGmtCreateStart(),
                    empPositionQuery.getGmtCreateEnd());
        }
        if (empPositionQuery.getCreateUserId() != null) {
            example.and().andLike("createUserId", "%" + empPositionQuery.getCreateUserId() + "%");
        }
        // 排序
        ExampleKit.setExampleOrder(example, empPositionQuery.getOrders());
        return example;
    }

    @Override
    public List<EmpPositionDO> listAllByPositionId(String companyId, String siteId, String... positionIds) {
        if (positionIds == null || CollectionUtils.isEmpty(Arrays.asList(positionIds))) {
            return null;
        }
        Example example = new Example(EmpPositionDO.class);
        example.and()
                .andIn("positionId", Arrays.asList(positionIds))
                .andEqualTo("companyId", companyId)
                .andEqualTo("siteId", siteId);

        return empPositionDAO.selectByExample(example);
    }

    @Override
    public List<EmpPositionDO> listAllByCompany(String companyId, String siteId) {
        Example example = new Example(EmpPositionDO.class);
        example.and()
                .andEqualTo("companyId", companyId)
                .andEqualTo("siteId", siteId);

        return empPositionDAO.selectByExample(example);
    }

    @Override
    public List<EmpPositionDO> listAllByEmpId(String companyId, String empId, String siteId) {
        Example example = new Example(EmpPositionDO.class);
        example.and()
                .andEqualTo("empId", empId)
                .andEqualTo("companyId", companyId)
                .andEqualTo("siteId", siteId);
        return empPositionDAO.selectByExample(example);
    }

    @Override
    public List<EmpPositionDO> selectByEmpIdList(List<String> empIdList, String siteId) {
        Example example = new Example(EmpPositionDO.class);
        example.and()
                .andIn("empId", empIdList)
                .andEqualTo("siteId", siteId);
        return empPositionDAO.selectByExample(example);
    }
}


